/*
 * text_paint.c
 *
 * Paints text onto screen.
 *
 * Copyright (c) 2010, Alan Green.
 * Contactable at <firstname>.<lastname>@gmail.com
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  1.  Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *  2.  Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 *
 * ===============================================
 */
#include "display.h"
#include "text_paint.h"

#include "vincent/vincent_slice.h"

//
// Paints line line of the chars in str, starting at cell cell
// 13c per char, plus overhead
void paint_chars(char * str, uint8_t cell, uint8_t line) {

    // original, slow code:
    //    uint8_t c = *(str++);
    //    uint8_t *s = vincent_slice[line];
    //    while (c) {
    //        uint8_t b = pgm_read_byte(&(s[c]));
    //        display_ram[cell] = b;
    //        cell++;
    //        c = *(str++);
    //    }

	asm volatile("\n"
			// Calculate vincent = vincent_slice[line]
			// First %[line]:r0 = %[line] * 128
			"    mov   r0, r1                ;                              \n"
			"    asr   %[line]               ; divide by 2 - lsb -> carry   \n"
			"    ror   r0                    ; put carry to top bit of r0   \n"
			// Add to Vincent
			"    adc   %A[vincent], r0       ; add to ...                   \n"
			"    adc   %B[vincent], %[line]  ;  ... vincent data pointer    \n"
			"    rjmp  2f                    ; go get first char            \n"
			"1:\n"
			// Get data, move to dram (7c)
			"    movw  r30, %[vincent]       ; set up Z                     \n"
			"    add   r30, r0               ; with pointer to bits         \n"
			"    lpm   r0, z                 ; grab the data                \n"
			"    st    y+, r0                ; put it in display ram        \n"
			"2:\n"
			// Fetch next char (5c)
			"    ld    r0, x+                ; get next char                \n"
			"    tst   r0                    ; is it NUL?                   \n"
			"    brne  1b                    ; output it                    \n"
            : // Outputs and modifies
            "+x" (str)
            : // Inputs
            [dram] "y" (display_ram + cell),
            [line] "r" (line),
            [vincent] "r" (vincent_slice)
    );
}
